package com.xyhy.starter.web.advice;

import java.util.HashSet;
import java.util.Set;

import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import com.xyhy.core.jackson.utils.JacksonUtil;
import com.xyhy.core.web.annotation.NoWrapper;
import com.xyhy.core.web.model.wrapper.Result;

@RestControllerAdvice
public class WrapperAdvice implements ResponseBodyAdvice<Object> {
  @SuppressWarnings("serial")
  private Set<Class<?>> notSupports = new HashSet<Class<?>>() {
    {
      // 规避对swagger的影响
      add(springfox.documentation.swagger2.web.Swagger2ControllerWebMvc.class);
      add(springfox.documentation.swagger.web.ApiResourceController.class);
      add(org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.class);
    }
  };

  @Override
  public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
    boolean isTypeNoWrapper = returnType.getDeclaringClass().isAnnotationPresent(NoWrapper.class);
    boolean isMethodNoWrapper = returnType.getMethod().isAnnotationPresent(NoWrapper.class);
    return !(notSupports.contains(returnType.getDeclaringClass()) || isTypeNoWrapper || isMethodNoWrapper);
  }

  @Override
  public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, //
                                Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ///
                                ServerHttpResponse response) {

    Object result = null;
    if (body instanceof Result) {
      result = body;
    } else if (body instanceof String) {
      // 因为StringHttpMessageConverter会直接把字符串写入body, 所以字符串特殊处理
      result = JacksonUtil.toJson(Result.success(body));
    } else {
      // 其他类型进行统一包装
      result = Result.success(body);
    }
    return result;
  }

}
